
//~ #include <map>
//#include <list>
#include <vector>
#include <cassert>
#include <iostream>
//~ #include <string>

using namespace std;

#include "alvo.hpp"
#include "alvo_stl.hpp"


struct A_CONT_TAG_Private {
	vector<ALVO*> items;
};

struct ALVO_runtime_Private {
	ALVO_X X;
	ALVO_C C;

	map<char*,ALVO*,ltstr> fns;
	typedef map<char*,ALVO*,ltstr>::iterator fns_iter;
	vector<ALVO*> items;
};

#if 0

ALVO*
eval (ALVO_runtime &frame, ALVO * /*const*/ i) {
	ALVO *x;
	x= eval(frame, i, NULL);
	return x;
}

ALVO *
alvo_x(ALVO_runtime &B) {
	A_LAZY*  A1=B.C.lazy();
	A_INT*  A2=B.C.int_(3, B.X.cont(*A1));
	A_EVAL* A3=B.C.eval("print", B.X.cont(*A1));
	//
	return A1;
}

ALVO_X ALVO_runtime::X;
ALVO_C ALVO_runtime::C;

void A_LAZY::add(ALVO*aa) {items.push_back(aa);}
void A_LIST::add(ALVO*aa) {items.push_back(aa);}
void  A_GRP::add(ALVO*aa) {items.push_back(aa);}

AH_CONT* ALVO_X::cont(A_CONT_TAG& ag) {
	AH_CONT* R=new AH_CONT;
	R->valid=true;
	R->c=&ag;
	return R;
}
A_GRP*  ALVO_C::group() { A_GRP * R=new A_GRP;  return R; }
A_LIST*  ALVO_C::list() { A_LIST* R=new A_LIST; return R; }
A_LAZY*  ALVO_C::lazy() { A_LAZY* R=new A_LAZY; return R; }

A_INT*   ALVO_C::int_(char* ais, AH_CONT*ak) {
	return int_(atoi(ais), ak);
}

A_INT*   ALVO_C::int_(int   ai, AH_CONT*ak) {
	A_INT* R=new A_INT;
	R->m=ai;
	assert(ak->valid);
	ak->c->add(R);
	return R;
}

AH_CONT& operator<< (AH_CONT &ak, ALVO &av) {
	ak.c->add(&av);
	return ak;
}

A_STR*   ALVO_C::stringular(char *as, AH_CONT*ak) {
	A_STR* R=new A_STR;
	R->m=as;
	assert(ak->valid);
	ak->c->add(R);
	// ak << R; // TODO: change method sig
	return R;
}

A_SYM*   ALVO_C::symbol(char *as, AH_CONT*ak) {
	A_SYM* R=new A_SYM;
	R->m=as;
	assert(ak->valid);
	ak->c->add(R);
	return R;
}

A_EVAL* ALVO_C::eval(char* ac, AH_CONT*ak) {
	A_EVAL* R=new A_EVAL;
	R->m=ac;
	assert(ak->valid);
	ak->c->add(R);
	return R;
}

ALVO_runtime* /*ALVO_runtime::*/base = new ALVO_runtime ();

void ALVO_runtime::push(ALVO*aa) {
	//assert(false);
	items.push_back(aa);
}

void AlvoM::print_int(int T) {printf("%d", T);}

ALVO* ALVO_runtime::pop() {
	ALVO *x=items.back();
	items.pop_back();
	return x;
}

void ALVO_runtime::eval(A_EVAL*ae) {
	//~ printf("ALVO_runtime::eval --> %s\n", ae->m);
	
	string scar, face(ae->m);
	
#define face1 ae->m


	if (strcmp("print", face1) == 0) {
//	if (face == "print") {
		ALVO *x=pop();
		
		//
		if (x->ac==AC_INTEGER) {
			AlvoM::print_int(((A_INT*)x)->m);
		} else {
			assert(false);
		}
	}else if (strcmp("def", face1) == 0) {
//	} else if (face == "def") {
		ALVO *fnname=pop();
		ALVO *fnbody=pop();
		fns[((A_STR*)fnname)->m] = fnbody;
	} else {
		ALVO *fnname=pop();
		char *cfnname=((A_STR*)fnname)->m;
		
		fns_iter ie=fns.end(),iff;
		iff=fns.find(cfnname);
		if (iff==ie) {
			assert(135==false);
		} else {
			ALVO *p=iff->second;
			::eval(*this, p);
		}
	}
}

//~ class SymStream {
//~ public:
//~ };

//~ #include "alvop.cch"

//~ #include <unistd.h>
//~ #include <sys/types.h>
//~ #include <sys/stat.h>
//~ #include <fcntl.h>

extern "C" {extern int rest(char*,void*);}

int main(void) {
	ALVO_runtime *B=new ALVO_runtime;
	ALVO *C=alvo_x(*B);
	eval(*B,C);
	//
	//~ if (0) {int fd=open("fib.alvo", O_RDONLY);
	//~ if (fd==-1) {return 999;};
	//~ char s[4096];
	//~ int bytes=read(fd,s,sizeof(s)-1);
	//~ s[4096]='\0';
	//~ assert(bytes>0);
	//~ int i=0;}
	//~ //AlvoP(s,i,*new SymStream);
	ALVO *CC=0;
	rest("fib11.alvo", &CC);
	//const 
	ALVO*CCC=CC;
	eval(*B,CCC);
	//
	return 0;
}

#endif

extern ALVO*
eval (ALVO_runtime &frame, ALVO *i, framestack_t *calling_stack);

ALVO*
eval_lazy (ALVO_runtime &frame, A_LAZY  *i, framestack_t *calling_stack) {
		A_LAZY &gr = 
			(A_LAZY&)*i;
		//ALVO  *ii = gr.first;
		vector<ALVO*>::iterator 
			ii=	gr.prv->items.begin(),
			ie= gr.prv->items.end();

		framestack_t *nst=
			enter_frame(frame, gr, calling_stack);
		
		// TODO use copy here
		while (ii!=ie) {
			eval(frame, *ii, nst);
			++ii;
			//ii=gr.next;
		}

}


void push_back(vector<class A> a, A&b) {
	a.push_back(b);
}
//template <class B>
//B& 
void stack_back(vector<class A> a) {
	return a.back();
}
template <class B>
B& pop_back(vector<class A> a) {
	return a.pop_back();
}




ALVO_C& 
c(ALVO_runtime &B) /*const*/ {
	return B.prv->C;
}
ALVO_X& 
x(ALVO_runtime &B) /*const*/ {
	return B.prv->X;
}

void items_push_back(int y,ALVO*aa) {y.items.push_back(aa);}

void ALVO_runtime::eval(A_EVAL*ae) {
	//~ printf("ALVO_runtime::eval --> %s\n", ae->m);
	
	string scar, face(ae->m);
	
#define face1 ae->m


	if (strcmp("print", face1) == 0) {
//	if (face == "print") {
		ALVO *x=pop();
		
		//
		if (x->ac==AC_INTEGER) {
			AlvoM::print_int(((A_INT*)x)->m);
		} else {
			assert(false);
		}
	}else if (strcmp("def", face1) == 0) {
//	} else if (face == "def") {
		ALVO *fnname=pop();
		ALVO *fnbody=pop();
		fns[((A_STR*)fnname)->m] = fnbody;
/*		hash_set(
				fns,
				c_str_of(fnname),
				fnbody
			);*/
	} else {
		ALVO *fnname=pop();
		char *cfnname=((A_STR*)fnname)->m;
		
		fns_iter ie=fns.end(),iff;
		iff=fns.find(cfnname);
		if (iff==ie) {
			assert(135==false);
		} else {
			ALVO *p=iff->second;
			::eval(*this, p);
		}
	}
}

ALVO* ALVO_runtime::pop() {
	ALVO *x=prv->items.back();
	items.pop_back();
	return x;
	// TODO
//	return NULL;
}
